package com.gitee.chili.leisure.core;

import cn.hutool.core.util.ReflectUtil;
import com.gitee.chili.leisure.ResponseCode;
import com.gitee.chili.leisure.exception.NettyEncodedException;
import com.gitee.chili.leisure.util.AuxiliaryChannel;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * 消息处理基础类
 */
@Slf4j
public class DefaultMessageHandler<T extends AbstractDefaultMessage> implements MessageHandler {

    /**
     * 消息参数
     * <p>
     * 执行了消息的解码，编码，传递
     */
    private final Class<? extends AbstractDefaultMessage> clazz;

    /**
     * 处理器执行的处理逻辑
     */
    private final Method method;

    /**
     * 消息隶属于那个类
     */
    private final Object obj;

    /**
     * 是否需要认证
     */
    private final boolean isAuthentication;


    public DefaultMessageHandler(Object obj, Method method, Class<? extends AbstractDefaultMessage> clazz, boolean isAuthentication) {
        this.obj = obj;
        this.method = method;
        this.clazz = clazz;
        this.isAuthentication = isAuthentication;
    }

    /**
     * 数据包解码
     *
     * @param packet  要解码的数据包
     * @param channel 数据包来源
     * @return 返回数据包对应的消息
     */
    public AbstractDefaultMessage cast(Packet packet, Channel channel) {
        try {
            return ReflectUtil.newInstance(clazz, packet, channel);
        } catch (Exception e) {
            log.error("解码 netty body 异常: [ {} ] , 命令: [ {} ]", packet.getBody(), packet.getCmd(), new NettyEncodedException(e));
            AuxiliaryChannel.errorMessage(channel, packet.getCmd(), ResponseCode.FAIL);
            return null;
        }
    }

    @Override
    public void onHandler(Packet packet, Channel channel) throws InvocationTargetException, IllegalAccessException {
        if (isAuthentication) {
            // TODO 开启认证
            AuxiliaryChannel.errorMessage(channel, packet.getCmd(), ResponseCode.UNAUTHORIZED);
            return;
        }

        log.debug("进行消息处理， 消息指令: [ {} ]", packet.getCmd());
        AbstractDefaultMessage message = cast(packet, channel);

        // 消息解析异常
        if (Objects.isNull(message)) {
            AuxiliaryChannel.errorMessage(channel, packet.getCmd(), ResponseCode.FAIL);
            return;
        }

        try {
            // 解码
            message.decoder();
        } catch (Exception e) {
            log.error("数据包解码异常: {}", e.getMessage(), e);
            return;
        }

        method.invoke(obj, message);
    }
}
